﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Web;
using Argotic.Syndication;
using WeMakeSP.Platform.SharePoint.MVP;

namespace WeMakeSP.WebComponents.RSSAdvancedReaderWebPart
{
    /// <summary>
    /// Represents the RSS advanced reader model.
    /// </summary>
    public class RSSAdvancedReaderModel : ModelBase, IRSSAdvancedReaderModel
    {
        #region Fields

        /// <summary>
        /// The rss feeds field.
        /// </summary>
        private Dictionary<string, RssFeed> rssFeedsField;

        #endregion

        #region Private Properties

        /// <summary>
        /// Gets the RSS feeds.
        /// </summary>
        /// <value>The RSS feeds.</value>
        private Dictionary<string, RssFeed> RSSFeeds
        {
            get
            {
                if (this.rssFeedsField == null)
                {
                    this.rssFeedsField =
                        new Dictionary<string, RssFeed>();
                }

                return this.rssFeedsField;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Gets the feed.
        /// </summary>
        /// <param name="url">The feed URL.</param>
        /// <returns>An RSS advanced reader feed.</returns>
        public RSSAdvancedReaderFeed GetFeed(string url)
        {
            // Guard.

            if (url == null)
            {
                throw new ArgumentNullException("url");
            }

            RSSAdvancedReaderFeed feed =
                new RSSAdvancedReaderFeed();

            RssFeed rssFeed =
                this.GetRSSFeed(url);

            // Set the feed status.

            feed.Status =
                (String.IsNullOrEmpty(rssFeed.Channel.Title) == true && rssFeed.Channel.Items.Count() == 0) ?
                    RSSAdvancedReaderFeedStatus.NotFound : RSSAdvancedReaderFeedStatus.Ok;

            switch (feed.Status)
            {
                case RSSAdvancedReaderFeedStatus.Ok:

                    // Set the feed title.

                    feed.Title = rssFeed.Channel.Title;

                    // Check if the feed have an image.

                    if (rssFeed.Channel.Image != null)
                    {
                        RssImage rssImage = rssFeed.Channel.Image;

                        // Set the feed image.

                        feed.Image =
                            new RSSAdvancedReaderImage()
                            {
                                Url = rssImage.Url,
                                Size = new Size(rssImage.Width, rssImage.Height)
                            };

                        // Indicate that the feed have an image.

                        feed.HaveImage = true;
                    }

                    // Set the last updated timestamp.

                    feed.LastUpdate = DateTime.Now;

                    // Set the rss url.

                    feed.Link = url;

                    foreach (RssItem item in rssFeed.Channel.Items)
                    {
                        feed.Items.Add(
                            new RSSAdvancedReaderFeedItem()
                            {
                                Description = item.Description,
                                Link = item.Link.OriginalString,
                                PublicationDate = item.PublicationDate,
                                Title = item.Title,
                            });
                    }

                    break;
                case RSSAdvancedReaderFeedStatus.NotFound:

                    // Set an empty url.

                    feed.Link = string.Empty;

                    string notFoundTitle =
                        string.Format(Properties.Resources.RES_FeedHostNotFound, url);

                    // Set the feed title.

                    feed.Title = notFoundTitle;
                    break;
                default:
                    throw new NotImplementedException("RSSAdvancedReaderFeedStatus");
            }

            // Returns.

            return feed;
        }

        /// <summary>
        /// Gets the feeds.
        /// </summary>
        /// <param name="urls">The feeds urls.</param>
        /// <returns>A collection of feeds.</returns>
        public RSSAdvancedReaderFeedCollection GetFeeds(string[] urls)
        {
            // Guard.

            if (urls == null)
            {
                throw new ArgumentNullException("urls");
            }

            RSSAdvancedReaderFeedCollection feeds =
                new RSSAdvancedReaderFeedCollection();

            // For each feed.

            foreach (string url in urls)
            {
                feeds.Add(this.GetFeed(url));
            }

            // Returns.

            return feeds;
        }

        /// <summary>
        /// Gets the items.
        /// </summary>
        /// <param name="url">The feed URL.</param>
        /// <returns>A collection of feed items.</returns>
        public RSSAdvancedReaderFeedItemCollection GetItems(string url)
        {
            // Guard.

            if (url == null)
            {
                throw new ArgumentNullException("url");
            }

            // Get the feed.

            RssFeed feed =
                this.GetRSSFeed(url);

            RSSAdvancedReaderFeedItemCollection feedItems =
                new RSSAdvancedReaderFeedItemCollection();

            foreach (RssItem item in feed.Channel.Items)
            {
                feedItems.Add(
                    new RSSAdvancedReaderFeedItem()
                    {
                        Description = item.Description,
                        Link = item.Link.OriginalString,
                        Title = item.Title
                    });
            }

            // Returns.

            return
                feedItems;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Gets the feed.
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        /// <returns>An RSS advanced reader feed.</returns>
        public RSSAdvancedReaderFeed GetFeed(RSSAdvancedReaderFeedConfiguration configuration)
        {
            RSSAdvancedReaderFeed feed;

            // Get the feed?

            if (configuration.Load == true)
            {
                feed =
                    this.GetFeed(configuration.Link);

                // Get the total items count.

                feed.TotalItems = feed.Items.Count;

                // Apply limit ?

                if (configuration.Limit > 0)
                {
                    IEnumerable<RSSAdvancedReaderFeedItem> limitedItems =
                        feed.Items.Take(configuration.Limit);

                    feed.Items =
                        new RSSAdvancedReaderFeedItemCollection();

                    feed.Items.AddRange(limitedItems);
                }

                // Display the show more items hyperlink?

                feed.ShowMoreItems = (feed.TotalItems == feed.Items.Count()) ? false : true;

                // Apply extra configurations to the feed.

                feed.Image.MaxSize =
                    new Size(configuration.MaxImageWidth, configuration.MaxImageHeight);

                feed.ShowImage = configuration.ShowImage & feed.HaveImage;

                // Apply extra configurations to the items.

                foreach (RSSAdvancedReaderFeedItem item in feed.Items)
                {
                    item.View = configuration.View;
                    item.ShowPublicationDate = 
                        configuration.ShowPublicationDate & item.PublicationDate > DateTime.MinValue;
                }
            }
            else
            {
                feed = new RSSAdvancedReaderFeed();
                feed.Link = configuration.Link;
            }

            // Returns.

            return feed;
        }

        /// <summary>
        /// Gets the feeds.
        /// </summary>
        /// <param name="configurations">The configurations.</param>
        /// <returns>A collection of feeds.</returns>
        public RSSAdvancedReaderFeedCollection GetFeeds(RSSAdvancedReaderFeedConfigurationCollection configurations)
        {
            // Guard.

            if (configurations == null)
            {
                throw new ArgumentNullException("configurations");
            }

            RSSAdvancedReaderFeedCollection feeds =
                new RSSAdvancedReaderFeedCollection();

            foreach (RSSAdvancedReaderFeedConfiguration configuration in configurations)
            {
                feeds.Add(this.GetFeed(configuration));
            }

            // Returns.

            return feeds;
        }

        /// <summary>
        /// Gets the RSS feed.
        /// </summary>
        /// <param name="url">The RSS feed URL.</param>
        /// <returns>The Rss feed.</returns>
        private RssFeed GetRSSFeed(string url)
        {
            // Guard.

            if (String.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }

            // Check if the feed has already been loaded.

            if (this.RSSFeeds.ContainsKey(url) == false)
            {
                RssFeed newFeed =
                    new RssFeed();

                try
                {
                    // Initialize the feed.

                    newFeed =
                        RssFeed.Create(new Uri(url));
                }
                catch (System.Net.WebException)
                {
                }

                // Add the feed to the dictionnary.

                this.RSSFeeds.Add(url, newFeed);
            }

            RssFeed feed =
                this.RSSFeeds[url];

            // Returns.

            return feed;
        }

        #endregion
    }
}
